﻿using System;
using System.Windows;
using System.Linq;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using Bling.DSL;
using Bling.WPF;
using Bling.Util;
using Bling.Physics;
using Bling.Animation;
using Bling.Properties;

namespace Bling.PhysicsTutorial {
  /// <summary>
  /// Higher level shape body example, demonstrates how mouse adapter can be used to control input. 
  /// </summary>
  public class Slinky : PhysicsCanvas {

    // Extend ParticlBody.Is to get particles for each body, pre-req for ShapeBody.Is
    // Extend ShapeBody.Is to get shape matching functionality
    // Extend MouseAdapter.Is to manipulate bodies with mouse (no thumbs needed)!
    public class CustomBlock : PhysicsBlock<Image, ImageBl, CustomBlock>,
      ParticleBody.Is<CustomBlock>, RigidBody.Is<CustomBlock>, ShapeBody.Is<CustomBlock>, MouseAdapter.Is<Image, CustomBlock> {
      public CustomBlock(World World, int Count, Func<int, Image> MakeT) : base(World, Count, MakeT) {
        // Must manually install particle body and shape body extensions. 
        new ParticleBody.Impl<CustomBlock>(this) {
          Loss = .2
        };
        new RigidBody.Impl<CustomBlock>(this);
        new ShapeBody.Impl<CustomBlock>(this);
        new MouseAdapter.Impl<Image,CustomBlock>(this);
      }
    }
    // image sources to use in example. 
    public static readonly ImageSourceBl[] Covers = new ImageSourceBl[] {
      Properties.Resources.rmb,
      Properties.Resources._100usd,
      Properties.Resources._500EUROV,
      Properties.Resources.chf1000_front,
    };
    static Slinky() {
      ParticleBody.Impl<CustomBlock>.ParticlesCount = 4;
    }

    public Slinky() : base("Slinky", 10) {
      this.Bl().Background = Brushes.Gray;
    }
    protected override Action Init(CanvasBl MainCanvas, World World) {
      CustomBlock block = new CustomBlock(World, 30, (idx) => {
        return new ImageBl(MainCanvas) {
          Source = Covers[(idx/5) % Covers.Length],
          Size = Covers[0].Size * .5,
        };
      }) { Name = "Slinky", };
      block.ShapePoints().BindRect(Covers[0].Size * .5);

      var Scatter = new ButtonBl(MainCanvas) {
        Content = "Scatter", LeftBottom = new PointBl(0, MainCanvas.Height),
        ToolTip = "Press to scatter money",
      };

      var Strength = new SliderBl(MainCanvas) {
        Width = MainCanvas.Width - Scatter.Width, 
        LeftBottom = new PointBl(Scatter.Width, MainCanvas.Height),
        Height = Scatter.Height,
        Minimum = 0, Maximum = 1, Value = 1,
      };
      Strength.ToolTip = "Constraint strength ".Bl() + Strength.Value;
      var Length = new SliderBl(MainCanvas) {
        Width = MainCanvas.Width, LeftBottom = new PointBl(0, Strength.Top),
        Minimum = 1, Maximum = 100, Value = 10,
      };
      Length.ToolTip = "Restlength ".Bl() + Length.Value;

      block.ShapeBodyE().RelaxNext = (block0) => {
        block0.ForAll(body => {
        });
      };
      block.CustomInit = (block0) => {
        block0.ConnectBlock();
        block0.ForAll(body => {
          body.Particles().ForAll(particle => {
            {
              var b = (particle.Index % 2) == (body.Index % 2);
              particle.Position.Relax[.5*Strength.Value, body.Index > 0 & b] =
                particle.Position.Spring(body.Prev[1].Particles(particle.Index).Position, Length.Value);
              particle.Position.Relax[.5*Strength.Value, body.Index < block.Count - 1 & b] =
                particle.Position.Spring(body.Next[1].Particles(particle.Index).Position, Length.Value);
            }
            particle.Position.Init = (new PointBl(1000, 1000) * new Random());
            particle.Position.Old = particle.Position.Old.Restitution(particle.Position, new Point(0, 0), MainCanvas.Size);
            particle.Position = particle.Position.Clamp(new PointBl(0, 0), MainCanvas.Size);

          });
        });
      };
      return () => {
        PointBl RandomPoint = new Random();
        // all blocks will be scattered
        var assign = PointBl.Assign<int, int>((i, j) => block[i].Particles(j).Position, (i, j) => RandomPoint * MainCanvas.Size);


        Scatter.Click = () => {
          for (int i = 0; i < block.Count; i++)
            for (int j = 0; j < block[i].Particles().Count; j++)
              assign(i,j);

        };
      
      };
    }
  }

}
